/*******************************************************************************

ADL SCORM 2004 4th Edition Sample Run-Time Environment

The ADL SCORM 2004 4th Ed. Sample Run-Time Environment is licensed under
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States.

The Advanced Distributed Learning Initiative allows you to:
  *  Share - to copy, distribute and transmit the work.
  *  Remix - to adapt the work. 

Under the following conditions:
  *  Attribution. You must attribute the work in the manner specified by the author or
     licensor (but not in any way that suggests that they endorse you or your use
     of the work).
  *  Noncommercial. You may not use this work for commercial purposes. 
  *  Share Alike. If you alter, transform, or build upon this work, you may distribute
     the resulting work only under the same or similar license to this one. 

For any reuse or distribution, you must make clear to others the license terms of this work. 

Any of the above conditions can be waived if you get permission from the ADL Initiative. 
Nothing in this license impairs or restricts the author's moral rights.

******************************************************************************/
package org.adl.validator.packagechecker.checks;

import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.adl.validator.packagechecker.PackageChecker;
import org.adl.validator.util.CheckerStateData;
import org.adl.validator.util.Messages;
import org.adl.validator.util.Result;
import org.adl.validator.util.ValidatorCheckerNames;
import org.adl.validator.util.ValidatorKeyNames;
import org.adl.validator.util.ValidatorMessage;
import org.adl.validator.util.processor.SchemaHandler;
import org.adl.validator.util.processor.URIHandler;

/**
 * This checker will ensure all required files and controlling documents are at
 * the root of the package
 * 
 * @author ADL Technical Team
 *
 */
public class RequiredFilesChecker extends PackageChecker
{
   /**
    * String representing the full path of the imsmanifest.xml file
    */
   private String mIMSManifestFile; 
   
   /**
    * String containing the full path of the package root
    */
   private String mRootDirectory;
   
   /**
    * SchemaHandler used to obtain the list of required files
    */
   private SchemaHandler mHandler;   
   
   /**
    * Default Constructor. Sets the attributes to their initial values.
    */
   public RequiredFilesChecker()
   {
      // default constructor
      
      mRootDirectory = 
         CheckerStateData.getInstance().getObjectValue(ValidatorKeyNames.ROOT_DIRECTORY_KEY).toString();
      
      mIMSManifestFile = mRootDirectory + 
         CheckerStateData.getInstance().getObjectValue(ValidatorKeyNames.XML_FILE_NAME_KEY);
      
      mHandler = new SchemaHandler(mIMSManifestFile); 
      
      mResult = new Result();
      mResult.setPackageCheckerName(ValidatorCheckerNames.REQ_FILES);  
   }
   

   public Result check()
   {
      mResult.setCheckerSkipped(false);
      
      if ( mIMSManifestFile == null || mRootDirectory == null )
      {
         mResult.addOverallStatusMessage(new ValidatorMessage(ValidatorMessage.FAILED,
         Messages.getString("RequiredFilesChecker.0")));
         mResult.setPackageCheckerPassed(false);
         mResult.setTestStopped(true);
         return mResult;
      }
      
      boolean passed = true;
      List schemaMessages;
      
      
      String fileList = mHandler.createRequiredFilesList();
 
      schemaMessages = mHandler.getErrorMessages();
      mResult.addPackageCheckerMessage(new ValidatorMessage(ValidatorMessage.INFO,
            Messages.getString("RequiredFilesChecker.1")));
      
      if ( schemaMessages != null )
      {
         Iterator schemaIter = schemaMessages.iterator();
         while ( schemaIter.hasNext() )
         {
            ValidatorMessage vMessage = (ValidatorMessage)schemaIter.next();
            if ( vMessage.getMessageType() == ValidatorMessage.FAILED )   
            {
               passed = false;
            }
            mResult.addPackageCheckerMessage(vMessage);
         }          
      }
      
      CheckerStateData.getInstance().setObject(ValidatorKeyNames.CONTROLLING_SCHEMAS_KEY, fileList);
      CheckerStateData.getInstance().addReservedKey(ValidatorKeyNames.CONTROLLING_SCHEMAS_KEY);
            
      if ( !fileList.equals("") )
      {
         String fileName = "";
         String requiredFiles[] = fileList.split(" ");
         List checkedRootFileList = new ArrayList();
         
         for ( int i = 0; i < requiredFiles.length; i++ )
         {
            fileName = requiredFiles[i];
            
            String rootFileName = fileName;
            rootFileName = rootFileName.replaceAll("/", File.separator + File.separator);
            int splitIndex = rootFileName.lastIndexOf(File.separator);
            
            if ( splitIndex >= rootFileName.length() - 2 )
            {
               passed = false;                
               mResult.addPackageCheckerMessage(new ValidatorMessage(ValidatorMessage.FAILED, 
                     Messages.getString("RequiredFilesChecker.2")));
            }
            else
            {
               rootFileName = rootFileName.substring(splitIndex+1);
               String rootFile = mRootDirectory + rootFileName;
               
               if ( !checkedRootFileList.contains(rootFile) )
               {
                  checkedRootFileList.add(rootFile);
                  if ( fileExists(rootFile) )
                  {
                     mResult.addPackageCheckerMessage(new ValidatorMessage(ValidatorMessage.PASSED,
                           Messages.getString("RequiredFilesChecker.3", rootFileName)));
                  }
                  else
                  {
                     passed = false;                
                     mResult.addPackageCheckerMessage(new ValidatorMessage(ValidatorMessage.FAILED, 
                           Messages.getString("RequiredFilesChecker.4", rootFileName)));
                  }
               }
            
               // if URL
               if ( URIHandler.isURL(requiredFiles[i]) )
               {
                  fileName = requiredFiles[i];
               }
               else
               {
                  fileName = mRootDirectory + requiredFiles[i];
               }

               // Check to see if the schema is located somewhere other than
               // the root and ensure it is present at that location
               if ( !rootFile.equals(fileName) )
               {
               
                  // Check specified location                  
                  if ( fileExists(fileName) )
                  {
                     mResult.addPackageCheckerMessage(new ValidatorMessage(ValidatorMessage.PASSED,
                           Messages.getString("RequiredFilesChecker.5", requiredFiles[i])));
                  }
                  else
                  {
                     passed = false;                
                     mResult.addPackageCheckerMessage(new ValidatorMessage(ValidatorMessage.FAILED, 
                           Messages.getString("RequiredFilesChecker.6", requiredFiles[i])));
                  }  
               }
            }
         }
      }
      
      if ( passed )
      {
         mResult.setPackageCheckerPassed(true);
         mResult.addOverallStatusMessage(new ValidatorMessage(ValidatorMessage.PASSED,
               Messages.getString("RequiredFilesChecker.7")));
         mResult.setTestStopped(false); 
      }
      else
      {
         mResult.setPackageCheckerPassed(false);
         mResult.addOverallStatusMessage(new ValidatorMessage(ValidatorMessage.FAILED,
               Messages.getString("RequiredFilesChecker.8")));
         mResult.setTestStopped(true);
      }
      
      String extensionMsg = mHandler.isExtensionsFound() ? Messages.getString("RequiredFilesChecker.9") :
                                            Messages.getString("RequiredFilesChecker.10");
      mResult.addOverallStatusMessage(new ValidatorMessage(ValidatorMessage.PASSED, extensionMsg));
      
      return mResult;
   }
   
   /**
    * Checks to make sure the URL File exists.
    * 
    * @param iFilePath is a String that represents the URL.
    * @return boolean that indicates is the file exists.
    */
   private boolean fileExists( String iFilePath )
   {
      boolean passed = true;

      try
      {
         if( URIHandler.isURL(iFilePath) )
         {
         
            URL url = new URL(iFilePath);
            URLConnection urlConn = url.openConnection();
            HttpURLConnection httpUrlConn = (HttpURLConnection)urlConn;
            int code = httpUrlConn.getResponseCode();
  
            if( code == HttpURLConnection.HTTP_OK )
            {
               mResult.addPackageCheckerMessage(new ValidatorMessage(ValidatorMessage.PASSED,
                     Messages.getString("RequiredFilesChecker.11", iFilePath)));
               passed = true;
            }
            else
            {
               mResult.addPackageCheckerMessage(new ValidatorMessage(ValidatorMessage.FAILED,
                     Messages.getString("RequiredFilesChecker.12", iFilePath)));
               passed = false;
            }
         
         }
         else
         {
            URIHandler uriHandler = new URIHandler();
            iFilePath = URIHandler.decode(iFilePath, URIHandler.ENCODING);
            iFilePath = uriHandler.escapeDirectories(iFilePath);
            iFilePath = iFilePath.replaceAll("/", File.separator + File.separator);
            
            File tempFile = new File(iFilePath);
         
            passed = tempFile.exists();
         }
      
      }
      catch( MalformedURLException mfue )
      {
         mResult.addPackageCheckerMessage(new ValidatorMessage(ValidatorMessage.FAILED,
               Messages.getString("RequiredFilesChecker.13", iFilePath)));
         passed = false;
      }
      catch( IOException ioe )
      {
         mResult.addPackageCheckerMessage(new ValidatorMessage(ValidatorMessage.FAILED,
               Messages.getString("RequiredFilesChecker.14", iFilePath)));
         passed = false;
      }
      
      return passed;
   }
}